#ifndef _SU_INTERFACE_H
#define _SU_INTERFACE_H

#ifdef SU_SOURCEMM
/**
 * @brief SourceMM Plugin Specific
 *
 * @{
 */
#define SUF_VERSION_ENGINE ""SUF_VERSION" MMS"
#define CMD_CONTINUE return
#define CMD_OVERRIDE RETURN_META(MRES_SUPERCEDE)
#include "ISmmPlugin.h"
	class CSourceUtilsFreeLib: public ISmmPlugin, public IGameEventListener2
	{
		/* Private Variables */
		int m_iClientCommandIndex;
		bool is_shutdown;

		/* Private Functions */
		//void* InterfaceSearch(CreateInterfaceFn factory, char *name);

	public:
		/* Public Functions */
		CSourceUtilsFreeLib();
		~CSourceUtilsFreeLib();

		const char *GetDescription();
		const char *GetVersion();

		bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late);
		bool Unload(char *error, size_t maxlen);
		bool Pause(char *error, size_t maxlen);
		bool Unpause(char *error, size_t maxlen);
		void AllPluginsLoaded(void);
		bool LevelInit(const char *pMapName, const char *pMapEntities, const char *pOldLevel, const char *pLandmarkName, bool loadGame, bool background);
		void ServerActivate(edict_t *pEdictList, int edictCount, int clientMax);
		void GameFrame(bool simulating);
		void LevelShutdown(void);
		bool ClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
		void ClientActive(edict_t *pEntity, bool bLoadGame);
		void ClientPutInServer(edict_t *pEntity, char const *playername);
		void ClientDisconnect(edict_t *pEntity);
		void SetCommandClient(int index);
		void ClientSettingsChanged(edict_t *pEdict);
		void ClientCommand(edict_t *pEntity); /* Use RETURN_META(MRES_SUPERCEDE) to override the gamedll */

		/* Some extra crap SourceMM requires */
		const char *GetName()
		{
			return "SourceUtils FreeLib";
		}

		const char *GetAuthor()
		{
			return "sn4k3";
		}

		const char *GetURL()
		{
			return "http://forums.alliedmods.net/showthread.php?t=52532";
		}

		const char *GetLicense()
		{
			return "GPL";
		}

		const char *GetDate()
		{
			return __DATE__;
		}

		const char *GetLogTag()
		{
			return "SourceUtils FreeLib";
		}

		/* IGameEventListener Interface */
		void FireGameEvent(IGameEvent *event); /* KeyValues *event */
	};

	//extern SourceHook::CallClass<IVEngineServer> *Engine_CC;

	PLUGIN_GLOBALVARS();
/** @} */
#else
#define SUF_VERSION_ENGINE ""SUF_VERSION" VSP"
#define CMD_CONTINUE return PLUGIN_CONTINUE
#define CMD_OVERRIDE return PLUGIN_STOP
#include "engine/iserverplugin.h"
class CSourceUtilsFreeLib: public IServerPluginCallbacks, public IGameEventListener2
{
public:
	CSourceUtilsFreeLib();
	~CSourceUtilsFreeLib();

	// IServerPluginCallbacks methods
	virtual bool			Load(	CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory );
	virtual void			Unload( void );
	virtual void			Pause( void );
	virtual void			UnPause( void );
	virtual const char     *GetPluginDescription( void );      
	virtual void			LevelInit( char const *pMapName );
	virtual void			ServerActivate( edict_t *pEdictList, int edictCount, int clientMax );
	virtual void			GameFrame( bool simulating );
	virtual void			LevelShutdown( void );
	virtual void			ClientActive( edict_t *pEntity );
	virtual void			ClientDisconnect( edict_t *pEntity );
	virtual void			ClientPutInServer( edict_t *pEntity, char const *playername );
	virtual void			SetCommandClient( int index );
	virtual void			ClientSettingsChanged( edict_t *pEdict );
	virtual PLUGIN_RESULT	ClientConnect( bool *bAllowConnect, edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen );
	virtual PLUGIN_RESULT	ClientCommand( edict_t *pEntity );
	virtual PLUGIN_RESULT	NetworkIDValidated( const char *pszUserName, const char *pszNetworkID );

	// IGameEventListener Interface
	virtual void FireGameEvent( IGameEvent * event );

	virtual int GetCommandIndex() { return m_iClientCommandIndex; }
private:
	int m_iClientCommandIndex;
};
#endif



#ifdef SU_SOURCEMM
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, 0, bool, char const *, char const *, char const *, char const *, bool, bool);
SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int, int);
SH_DECL_HOOK1_void(IServerGameDLL, GameFrame, SH_NOATTRIB, 0, bool);
SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, 0);
SH_DECL_HOOK2_void(IServerGameClients, ClientActive, SH_NOATTRIB, 0, edict_t *, bool);
SH_DECL_HOOK1_void(IServerGameClients, ClientDisconnect, SH_NOATTRIB, 0, edict_t *);
SH_DECL_HOOK2_void(IServerGameClients, ClientPutInServer, SH_NOATTRIB, 0, edict_t *, char const *);
SH_DECL_HOOK1_void(IServerGameClients, SetCommandClient, SH_NOATTRIB, 0, int);
SH_DECL_HOOK1_void(IServerGameClients, ClientSettingsChanged, SH_NOATTRIB, 0, edict_t *);
SH_DECL_HOOK5(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, edict_t *, const char*, const char *, char *, int);
SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
//SH_DECL_HOOK2(IGameEventManager2, FireEvent, SH_NOATTRIB, 0, bool, IGameEvent *, bool);
#endif

void *InterfaceSearch(CreateInterfaceFn factory, char *name)
{
	char *iface_str, *buf;
	unsigned int len, check, i;
	void *iface;

	if(name == NULL)
		return NULL;

	/* First test if this already a valid interface name */
	iface = factory(name, NULL);
	if(iface != NULL)
		return iface;

	len = strlen(name);
	iface_str = (char*)calloc(len+1, sizeof(char));
	strcpy(iface_str, name);

	if(len > 3) {
		check = isdigit(*(iface_str+(len-3))) ? 1 : 0;
		check &= isdigit(*(iface_str+(len-2))) ? 1 : 0;
		check &= isdigit(*(iface_str+(len-1))) ? 1 : 0;
		if(check)
			iface_str[len-3] = '\0';
	}

	buf = (char*)calloc(strlen(iface_str)+8, sizeof(char));

	for(i = 0;i < 1000;i++) {
		sprintf(buf, "%s%0.3d", iface_str, i);
		iface = factory(buf, NULL);
		if(iface != NULL)
			break;
	}

	free(iface_str);
	free(buf);
	return iface;
}

#endif
